﻿#include "Server_userConnect.h"
#include "GlobalMsg.h"
#include "iostream"

using namespace std;

Server_userConnect::Server_userConnect(uint16_t port,uint32_t usrNum)
    :maxUserNum(usrNum)
{
    //创建服务,绑定事件
    this->server = new QTcpServer;
    //QAbstractSocket::connect(this->server, &QTcpServer::newConnection,OnTcpConnect);//连接用户接入
    this->server->setMaxPendingConnections(100); //设置最大连接处理数，注意是某一时刻处理量，不是连接数量


    QAbstractSocket::connect(this->server,&QTcpServer::newConnection,[&](){
        this->OnTcpConnect();
        cout << "client connection!" << endl;
    });


    if(this->server->listen(QHostAddress::Any,port) == false){
        this->server->close();
        this->server = nullptr;
        cout << "Error: port listening failed!" << endl;
    }
}

Server_userConnect::~Server_userConnect()
{
    this->server->close();
    if(this->server != nullptr)
        delete this->server;
}


//判断是否有效
bool Server_userConnect::isValid()
{
    return this->server != nullptr;
}


//用户进入
void Server_userConnect::OnTcpConnect()
{
    //这里的循环表示可能多个客户端接入，防止遗漏造成堵塞
    while(this->server->hasPendingConnections()){
        QTcpSocket * tSocket = this->server->nextPendingConnection();

        //判断临时用户长度是否超额，超额则断开
        if(this->usrList.length() >= this->maxUserNum){
            this->server->disconnect(tSocket); //断开链接
            break;
        }

        //输出TCP临时链接
        //std::cout<<"TCP Connect ->" <<  tSocket->peerAddress().toString().toStdString() <<":"<<tSocket->peerPort() <<std::endl;


        //连接数据
        QAbstractSocket::connect(tSocket,&QTcpSocket::readyRead,[=](){
            OnTcpReadyRead(tSocket);
        }); //链接收到数据

        QAbstractSocket::connect(tSocket,&QTcpSocket::disconnected,[=](){
            OnTcpDisConnect(tSocket);
        }); //链接断开连接


        //        //添加临时信息到
        //        clientMsg t_clientMsg;
        //        t_clientMsg.tcp_Socket = tSocket; //零时记录TcpSocket，若验证通过则加入到长连接
        //        t_clientMsg.time_connect = QDateTime::currentDateTime();
        //        t_clientMsg.passwdId = tSocket->peerPort();
        //        this->usrList.append(t_clientMsg);


        //返回端口数据,进行数据验证
        QByteArray t_data;
        t_data.append({'\1'}); //返回需要的ID信息
        //t_data.append(QByteArray::number(t_clientMsg.passwdId));  //添加端口信息
        tSocket->write(t_data); //发送返回的
    }
}

//服务器TCP收到数据
void Server_userConnect::OnTcpReadyRead(QTcpSocket *tSocket)
{
    QByteArray t_data = tSocket->readAll(); //==============获取数据信息
    if(t_data.at(0) == '\0'){ //呼吸包
        QByteArray t_reData;
        t_reData.append({'\0'});
        tSocket->write(t_reData); //回应心跳信息
    }
    else if(t_data.at(0) == '\1'){ //==============客户端返回用户ID
        QString t_id = QString(t_data.right(t_data.length() - 1)); //获取ID信息
        QByteArray t_reData;
        if(t_id.isEmpty()){ //数据为空，则要求重新发送
            t_reData.append({'\1'}); //再次要求客户端发送ID数据
            tSocket->write(t_reData);
        }
        else{
            this->addUser(t_id,tSocket);
            t_reData.append({'\2'}); //通知客户端已经加入用户组
            tSocket->write(t_reData);
            //this->addUser(t_id,tSocket);

            cout << "user join:" << t_id.toStdString() << ", valid user: " << this->usrList.length() << endl;
        }
    }
    else if(t_data.at(0) == '\2'){ //==============用户请求获取在线监视列表
        QString t_serL; //持久列表字符串信息
        for(QList<serverMsg>::iterator si = this->serverList.begin(); si < this->serverList.end(); si++){
            if(si->usrSocket == tSocket){
                t_serL.append(si->proxyName + "&&&");
                if(si->type == serverType::TcpServer){ //保存服务类型
                    t_serL.append("tcp&&&"); //'\t'为元素分隔符
                    t_serL.append(QString::number(si->tcpServer->serverPort()) + "&&&");
                }
                else{
                    t_serL.append("udp&&&");
                    t_serL.append(QString::number(si->udpServer->localPort()) + "&&&");
                }
                t_serL.append(QString::number(si->proxyPort) + "&&&");

                if(si->persistent){
                    t_serL.append("persistent");
                }
                else{
                    t_serL.append("not persistent");
                }
                t_serL.append('\n');
            }
        }
        if(t_serL.isEmpty()) return;
        tSocket->write('\3' + t_serL.toLocal8Bit());

    }
    else if(t_data.at(0) == '\3'){ //==============映射的用户本地服务器回发TCP数据
        //数据结构: 数据结构: 客户标记 + 本地映射端口 + 转发数据
        QList<QByteArray> t_msg = packManger::parserData(t_data.right(t_data.length() - 1));
        if(t_msg.length() != 3) return;

        QString t_tcpClientSign = t_msg[0];
        uint16_t t_proxyPort = t_msg[1].toUInt();

        //定位客户，客户的服务器，客户服务器的用户
        QTcpSocket* t_netSocket = this->getTcpSocket(tSocket,t_tcpClientSign,t_proxyPort); //获取外网的Socket
        if(t_netSocket){
            t_netSocket->write(t_msg[2]); //将数据转发回外网
        }

    }
    else if(t_data.at(0) == '\4'){ //==============映射的用户本地服务器断开连接
        //数据结构: 客户标记 + 本地映射端口
        QList<QByteArray> t_msg = packManger::parserData(t_data.right(t_data.length() - 1));
        if(t_msg.length() != 2) return;

        QString t_tcpClientSign = t_msg[0];
        uint16_t t_proxyPort = t_msg[1].toUInt();

        QTcpSocket* t_netSocket = this->getTcpSocket(tSocket,t_tcpClientSign,t_proxyPort); //获取外网的Socket
        if(t_netSocket){
            this->removeProxyTcpUser(tSocket,t_netSocket,t_proxyPort); //同步断开外网连接的客户
        }
    }
    else if(t_data.at(0) == '\5'){ //==============映射的用户本地服务器回发UDP数据
        //数据结构: 本地映射端口 + 远程Host + 远程Port + 转发数据
        QList<QByteArray> t_msg = packManger::parserData(t_data.right(t_data.length() - 1));
        if(t_msg.length() != 4) return;
        uint16_t t_proxyPort = t_msg[0].toUInt();
        QString t_netHost = t_msg[1];
        uint16_t t_netPort = t_msg[2].toUInt();

        QUdpSocket* t_UdpServer = this->getUdpSocket(tSocket,t_proxyPort);
        if(t_UdpServer){
            t_UdpServer->writeDatagram(t_msg[3],QHostAddress(t_netHost),t_netPort); //数据转发
        }
    }
    else if(t_data.at(0) == '\6'){ //==============添加映射服务
        //添加远程代理，数据结构: 映射名称 + 远程协议 + 远程端口 + 本地映射端口 + 持久化逻辑
        QList<QByteArray> t_msg = packManger::parserData(t_data.right(t_data.length() - 1));

        if(t_msg.length() != 5) return;

        QString t_userID = this->getUserId(tSocket);
        QString t_name = t_msg[0];
        bool t_isTcp = (t_msg[1].toStdString() == "tcp");
        uint16_t t_listenPort = t_msg[2].toUInt();
        uint16_t t_proxyPort = t_msg[3].toUInt();
        bool t_persistent = (t_msg[4].toStdString() == "true");

        if(t_isTcp){
            this->addProxyTcpServer(t_name,t_userID,tSocket,t_listenPort,t_proxyPort,t_persistent);
        }
        else{
            this->addProxyUdpServer(t_name,t_userID,tSocket,t_listenPort,t_proxyPort,t_persistent);
        }

        cout << "user:" << t_userID.toStdString() << ",add proxy:" << t_msg[0].toStdString() << " " << t_listenPort << " " << t_proxyPort<< "   ,persistent" << t_persistent << endl;
    }
    else if(t_data.at(0) == '\7'){ //==============移除映射服务
        //移除远程代理，数据结构：本地映射端口
        QList<QByteArray> t_msg = packManger::parserData(t_data.right(t_data.length() - 1));
        if(t_msg.length() != 1) return;
        uint16_t t_listenPort = t_msg[0].toUInt();
        this->removeProxy(tSocket,t_listenPort); //移除映射信息
    }
}


//用户断开连接
void Server_userConnect::OnTcpDisConnect(QTcpSocket *tSocket)
{
    QString t_id;
    for(QList<usrMsg>::iterator ci = this->usrList.begin(); ci < this->usrList.end(); ci++){
        if((*ci).socket == tSocket){
            t_id = (*ci).usrID;
            break;
        }
    }
    if(!t_id.isEmpty()) this->removeUser(t_id); //移除用户信息
    cout << "user exit: " << this->usrList.length() << endl;
}

//添加用户信息，如果用户存在，则清理存在的信息
void Server_userConnect::addUser(QString id, QTcpSocket *socket)
{
    //移除在线用户信息
    this->Server_userConnect::removeUser(id);

    //添加用户信息到列表
    this->usrList.append({socket,id,""}); //添加新客户信息

    //将服务器对象信息刷新
    for(QList<serverMsg>::iterator si = this->serverList.begin(); si < this->serverList.end(); si++){
        if(si->usrID == id){
            si->usrSocket = socket; //设置新的返回socket


            if(si->type == serverType::TcpServer){
                QAbstractSocket::disconnect(si->tcpServer,0,0,0); //断开所有的信号槽
                QAbstractSocket::connect(si->tcpServer,&QTcpServer::newConnection,[=](){
                    this->OnProxyServerTcpConnect(si->tcpServer,si->usrSocket,si->proxyPort);
                }); //绑定连接服务器
            }
            if(si->type == serverType::UdpServer){
                QAbstractSocket::disconnect(si->udpServer,0,0,0); //断开所有的信号槽
                QAbstractSocket::connect(si->udpServer,&QUdpSocket::readyRead,[=](){
                    //服务套接字，客户套接字，客户远程转发端口
                    this->OnProxyServerUdpReadyRead(si->udpServer,si->usrSocket,si->proxyPort);
                }); //绑定UDP收到数据
            }
        }
    }
}


//移除在线用户
bool Server_userConnect::removeUser(QString id)
{
    for(QList<usrMsg>::iterator ci = this->usrList.begin(); ci < this->usrList.end();ci++){
        if((*ci).usrID == id){
            if((*ci).socket != nullptr){
                this->server->disconnect((*ci).socket); //服务器主动断开连接
            }

            //遍历服务器信息，移除服务器的临时在线信息
            for(QList<serverMsg>::iterator si = this->serverList.begin(); si < this->serverList.end(); si++){
                if(si->usrID == id){
                    if(si->persistent){ //判断是否为持久的信息保持
                        //si->usrSocket->close();//服务器断开连接
                        si->usrSocket = nullptr; //质控socket指针

                        //持久信息中，用户不存在，则拒绝所有消息
                        if(si->type == serverType::TcpServer){
                            QAbstractSocket::disconnect(si->tcpServer,0,0,0); //断开所有的信号槽
                            QAbstractSocket::connect(si->tcpServer,&QTcpServer::newConnection,[=](){
                                //用户不存在，断开所有连接
                                while(si->tcpServer->hasPendingConnections()){
                                    QTcpSocket* t_conSocket = si->tcpServer->nextPendingConnection();
                                    t_conSocket->close();
                                }
                            });
                        }
                        if(si->type == serverType::UdpServer){
                            QAbstractSocket::disconnect(si->udpServer,0,0,0); //断开所有的信号槽
                        }
                    }
                    else{
                        //非持久保存的信息，删除监听对象。
                        if(si->type == serverType::TcpServer){
                            if(si->tcpServer != nullptr) delete si->tcpServer;
                        }
                        else{
                            if(si->udpServer != nullptr) delete si->udpServer;
                        }
                        this->serverList.erase(si); //移除服务器信息
                    }
                }
            }

            //移除在线客户信息
            this->usrList.erase(ci);
            return true;
        }
    }
    return false;
}


//获取用户的文本ID
QString Server_userConnect::getUserId(QTcpSocket *socket)
{
    for(QList<usrMsg>::iterator ci = this->usrList.begin(); ci < this->usrList.end();ci++){
        if((*ci).socket == socket){
            return (*ci).usrID;
        }
    }
    return "";
}



//获取TCP唯一链接标志
QString Server_userConnect::getTcpAddressSign(QTcpSocket *socket)
{
    QHostAddress t_host = socket->peerAddress();
    uint16_t t_port = socket->peerPort();
    return t_host.toString() + ":" + QString::number(t_port);
}


//获取UDP唯一链接标志
QString Server_userConnect::getUdpAddressSign(QHostAddress host, quint16 port)
{
    return host.toString() + ":" + QString::number(port);
}


//根据AddressSign获取TCP指针
QTcpSocket *Server_userConnect::getTcpSocket(QTcpSocket *userSocket, QString AddressSign, uint16_t proxyPort)
{
    //便利循环用户列表
    for(QList<serverMsg>::iterator si = this->serverList.begin(); si < this->serverList.end(); si++){
        if(si->usrSocket == userSocket && si->proxyPort == proxyPort && si->type == serverType::TcpServer){
            //查找到对应用户，开始分配数据，进行数据转发
            if(si->tcpServer != nullptr){
                QObjectList t_clients = si->tcpServer->children();

                foreach (QObject* client, t_clients) {
                    QTcpSocket* socket = qobject_cast<QTcpSocket*>(client);
                    if (socket != nullptr && this->getTcpAddressSign(socket) == AddressSign) {
                        return socket;
                    }
                }
            }
            break;
        }
    }
    return nullptr;
}

//获取UDP服务器指针，这里不需要获取连接的Socket，因为UDP不面向连接
QUdpSocket *Server_userConnect::getUdpSocket(QTcpSocket *userSocket,uint16_t proxyPort)
{
    for(QList<serverMsg>::iterator si = this->serverList.begin(); si < this->serverList.end(); si++){
        if(si->usrSocket == userSocket && si->proxyPort == proxyPort && si->type == serverType::UdpServer){
            return si->udpServer;
        }
    }
    return nullptr;
}


//检查端口是否被占用
bool Server_userConnect::checkPort(uint16_t port)
{
    QTcpServer t_s;
    return t_s.listen(QHostAddress::Any,port);
}


//获取有效端口
uint16_t Server_userConnect::getPort(uint16_t srcPort)
{
    for(;srcPort < 65535;srcPort++){
        if(this->checkPort(srcPort)){
            return srcPort;
        }
    }
    return 0;
}



//添加TCP监视服务
void Server_userConnect::addProxyTcpServer(QString proxyName, QString userId, QTcpSocket *userSocket, uint16_t listenPort, uint16_t proxyPort, bool persistent)
{
    for(QList<serverMsg>::iterator i = this->serverList.begin(); i < this->serverList.end(); i++){
        if(i->proxyPort == proxyPort && i->type == serverType::TcpServer){ //如果端口存在则不再次创建
            return;
        }
    }

    if(listenPort == 0) listenPort = 81; //默认从81开始
    listenPort = this->getPort(listenPort);
    if(listenPort == 0) return; //端口全部被占用，不再添加监视信息

    serverMsg t_sm;
    t_sm.usrSocket = userSocket;
    t_sm.usrID = userId;
    t_sm.proxyName = proxyName;
    t_sm.type = serverType::TcpServer;
    t_sm.proxyPort = proxyPort;
    t_sm.persistent = persistent;
    t_sm.tcpServer = new QTcpServer;


    //    //连接数据
    //    QAbstractSocket::connect(tSocket,&QTcpSocket::readyRead,[=](){
    //        OnTcpReadyRead(tSocket);
    //    }); //链接收到数据

    //    QAbstractSocket::connect(tSocket,&QTcpSocket::disconnected,[=](){
    //        OnTcpDisConnect(tSocket);
    //    }); //链接断开连接

    QAbstractSocket::connect(t_sm.tcpServer,&QTcpServer::newConnection,[=](){
        this->OnProxyServerTcpConnect(t_sm.tcpServer,t_sm.usrSocket,t_sm.proxyPort);
    }); //绑定连接服务器
    t_sm.tcpServer->listen(QHostAddress::Any,listenPort);
    this->serverList.append(t_sm); //保存服务器列表信息
}


//添加UDP监视服务
void Server_userConnect::addProxyUdpServer(QString proxyName, QString userId, QTcpSocket *userSocket, uint16_t listenPort, uint16_t proxyPort, bool persistent)
{
    for(QList<serverMsg>::iterator i = this->serverList.begin(); i < this->serverList.end(); i++){
        if(i->proxyPort == proxyPort && i->type == serverType::UdpServer){ //如果监视的端口存在则不再次创建
            return;
        }
    }

    if(listenPort == 0) listenPort = 81; //默认从81开始
    listenPort = this->getPort(listenPort);
    if(listenPort == 0) return; //端口全部被占用，不再添加监视信息

    serverMsg t_sm;
    t_sm.usrSocket = userSocket;
    t_sm.usrID = userId;
    t_sm.proxyName = proxyName;
    t_sm.type = serverType::UdpServer;
    t_sm.proxyPort = proxyPort;
    t_sm.persistent = persistent;
    t_sm.udpServer = new QUdpSocket;

    QAbstractSocket::connect(t_sm.udpServer,&QUdpSocket::readyRead,[=](){
        //服务套接字，客户套接字，客户远程转发端口
        this->OnProxyServerUdpReadyRead(t_sm.udpServer,t_sm.usrSocket,t_sm.proxyPort);
    }); //绑定UDP收到数据

    t_sm.udpServer->bind(QHostAddress::Any,listenPort);
    this->serverList.append(t_sm); //保存服务器列表信息
}


//移除映射信息
void Server_userConnect::removeProxy(QTcpSocket *userSocket, uint16_t proxyPort)
{
    for(QList<serverMsg>::iterator i = this->serverList.begin(); i < this->serverList.end(); i++){
        if(i->usrSocket == userSocket && i->proxyPort == proxyPort){ //移除映射信息
            if(i->type == serverType::UdpServer){
                delete i->udpServer;
            }
            else{
                delete i->tcpServer;
            }
            this->serverList.erase(i);
            break;
        }
    }
}


//断开映射的服务器TCP的某一个用户
void Server_userConnect::removeProxyTcpUser(QTcpSocket * userSocket,QTcpSocket *connectSocket, uint16_t proxyPort)
{
    for(QList<serverMsg>::iterator i = this->serverList.begin(); i < this->serverList.end(); i++){
        if(i->proxyPort == proxyPort && i->type == serverType::TcpServer && i->usrSocket == userSocket){ //如果端口存在则不再次创建
            if(i->tcpServer){
                connectSocket->close();
                //i->tcpServer->disconnect(connectSocket);
                return;
            }
        }
    }
}


//映射TCP用户进入(1.映射服务器， 2.映射目标TCP， 映射目标端口)
void Server_userConnect::OnProxyServerTcpConnect(QTcpServer* proxyServer, QTcpSocket *userSocket, uint16_t proxyPort)
{
    //这里的循环表示可能多个客户端接入，防止遗漏造成堵塞
    while(proxyServer->hasPendingConnections()){
        QTcpSocket * tSocket = proxyServer->nextPendingConnection(); //tSocket为映射服务器连接的用户

        //连接数据
        QAbstractSocket::connect(tSocket,&QTcpSocket::readyRead,[=](){
            this->OnProxyServerTcpReadyRead(tSocket,userSocket,proxyPort); //将谁发来的数据与映射端口获取
        }); //链接收到数据

        QAbstractSocket::connect(tSocket,&QTcpSocket::disconnected,[=](){
            this->OnProxyServerTcpDisConnect(tSocket,userSocket);
        }); //链接断开连接

        //发送用户接入信息:  客户标记 + 映射端口标记
        QByteArray t_sendData;
        t_sendData.append('\4');
        t_sendData.append(packManger::buildData({this->getTcpAddressSign(tSocket).toLocal8Bit(),QByteArray::number(proxyPort)}));
        userSocket->write(t_sendData); //发送客户进入信息
    }
}



//服务器映射TCP收到数据（1.映射用户套接字  2.映射客户套接字， 3.客户远程映射端口）
void Server_userConnect::OnProxyServerTcpReadyRead(QTcpSocket *tSocket, QTcpSocket *userSocket, uint16_t proxyPort)
{
    //使用主线TCP转发数据
    QByteArray t_data = tSocket->readAll(); //解析数据
    QString t_userHost = this->getTcpAddressSign(tSocket);

    //发送用户接入信息:  客户标记 + 映射端口标记 + 转发数据
    QByteArray t_sendData;
    t_sendData.append('\5');
    t_sendData.append(packManger::buildData({t_userHost.toLocal8Bit(),QByteArray::number(proxyPort),t_data}));
    userSocket->write(t_sendData); //发送客户进入信息
}


//映射TCP用户断开连接
void Server_userConnect::OnProxyServerTcpDisConnect(QTcpSocket *tSocket, QTcpSocket *userSocket)
{
    QString t_userHost = this->getTcpAddressSign(tSocket);

    //发送用户接入信息:  客户标记
    QByteArray t_sendData;
    t_sendData.append('\6');
    t_sendData.append(packManger::buildData({t_userHost.toLocal8Bit()}));
    userSocket->write(t_sendData); //发送客户进入信息
}


//服务器映射UDP收到数据,转发给本地客户端处理
void Server_userConnect::OnProxyServerUdpReadyRead(QUdpSocket * udpServer, QTcpSocket *userSocket, uint16_t proxyPort)
{
    // 读取数据
    QByteArray t_datagram; //UDP数据
    t_datagram.resize(udpServer->pendingDatagramSize());
    QHostAddress t_senderAddress; //客户地址
    quint16 t_senderPort; //客户端口
    udpServer->readDatagram(t_datagram.data(), t_datagram.size(), &t_senderAddress, &t_senderPort);
    QString t_userHost = this->getUdpAddressSign(t_senderAddress,t_senderPort);

    //发送用户接入信息:  数据结构: 外网用户Host + 外网用户Port + 映射端口标记 + 转发数据
    QByteArray t_sendData;
    t_sendData.append('\7');
    t_sendData.append(packManger::buildData({t_senderAddress.toString().toLocal8Bit(),QByteArray::number(t_senderPort),QByteArray::number(proxyPort),t_datagram}));

    //udpServer->writeDatagram()
    userSocket->write(t_sendData); //发送客户进入信息
}

